home *** CD-ROM | disk | FTP | other *** search
- /* timezone.c
- */
- #include <time.h>
-
- /* Day number of first Sunday in April and last Sunday in October */
- int dst_start,dst_end;
-
-
- int daylight = 0; /* non-zero if local timezone uses DST */
-
- /* Cumulative days per month. Used to figure out first or last Sunday
- in a month. For the first Sunday in a month start with the cumulative
- number of days in the previous month. For the last Sunday in a month
- use the cumulative days for that month minus 7.
- The time routine uses Jan 1st as day zero.
- */
- int dpm[12] = {31,59,90,120,151,181,212,243,273,304,334,365};
-
- /* Find a timezone string. If s is a non-null string, use it.
- Otherwise check for the environment variable TZ_CHU in the system
- or Manx.
- If there's nothing valid, return -900 which is an impossible number
- of minutes for the correction to UTC.
- */
- gettz(s)
- char *s;
- {
- register char *p;
- extern int zone();
- char zonestr[10];
- zonestr[0] = 0;
- if(s && *s) {
- strcpy(zonestr,s);
- }
- else {
- /* Get the local time zone */
- p = getenv("TZ_CHU");
- if(p)strcpy(zonestr,p);
- else {
- /* If system one isn't there, try the MANX one */
- p = getenv("MANX/TZ_CHU");
- if(p)strcpy(zonestr,p);
- }
- }
- if(zonestr[0] == 0) {
- printf("ERROR: Timezone is not set in default file nor in TZ_CHU\n");
- return(-900); /* -900 is an impossible number of minutes which is
- tested for later in the program
- */
- }
- else {
- return(zone(&zonestr[0]));
- }
- }
-
- /* Get timezone in number of minutes east(-ve) or west(+ve) of Greenwich.
- Return number of minutes represented by the string in *s.
- Set the daylight flag if the string ends with a valid DST indicator.
- */
- zone(s)
- char *s;
- {
- register char *p,sign;
- register long adj;
-
- p = s;
- while((*p == ' ') || (*p == '\t'))p++;
- sign = 1;
- if(*p == '-') {
- p++;
- sign = -1;
- }
- adj = atoi(p)*60;
- while(isdigit(*p))p++;
- if(*p == ':') {
- p++;
- adj += atoi(p);
- while(isdigit(*p))p++;
- }
- switch(*p) {
- case 'd': /* North America - begin April to end October */
- case 'D':
- case 'u': /* U.K. - end March to end October */
- case 'U':
- case 'e': /* Europe + CIS - end March to end September */
- case 'E':
- case 'c': /* China - Apr 12 to Sept 12 */
- case 'C':
- daylight = *p;
- }
- /* The adjustment cannot exceed 12 hours */
- if(adj > 720) {
- printf("ERROR: timezone correction is too large\n");
- daylight = 0;
- return(-900);
- }
- return(adj*sign);
- }
-
- /*
- If daylight savings not used, or not currently in effect then just
- return the local standard time adjustment. Otherwise correct the
- standard time adjustment for daylight savings time.
- Need local day of the year (1-366), local hour (0-23)
- and standard timezone adjustment in minutes.
- */
- dst(adjust)
- int adjust;
- {
- /* adjust is the local standard time in minutes east(-ve) or west(+ve)
- of Greenwich. This routine checks to see if daylight savings time
- is required and, if so and daylight savings is in effect, the local
- standard time is adjusted accordingly
- */
- short day,hour;
- time_t ltime;
- register struct tm *tp;
- int dstflag;
-
- if(!daylight)return(adjust);
-
- dstflag = 0;
- time(<ime);
- tp = localtime(<ime);
- day = tp->tm_yday + 1;
- hour = tp->tm_hour;
-
- /* Northern Hemisphere */
- if((daylight >= 'a') && (daylight <= 'z')) {
- if((day < dst_start) || (day > dst_end))return(adjust);
-
- /* Now: if DST is in effect, determine if it should be applied */
- if((day > dst_start) && (day < dst_end))dstflag++;
- else if((day == dst_end) && (hour < 2))dstflag++;
- else if((day == dst_start) && (hour >= 2))dstflag++;
- if(dstflag) {
- adjust -= 60;
- }
- }
- else {
- /* Southern Hemisphere */
- if((day > dst_start) && (day < dst_end))return(adjust);
-
- /* Now: if DST is in effect, determine if it should be applied */
- if((day < dst_start) || (day > dst_end))dstflag++;
- else if((day == dst_end) && (hour < 2))dstflag++;
- else if((day == dst_start) && (hour >= 2))dstflag++;
- if(dstflag) {
- adjust -= 60;
- }
- }
- return(adjust);
- }
-
- /*
- The definition of DST in North America is the first Sunday in April
- to the last Sunday in October.
- For the U.K. it is last Sunday in March to last Sunday in October.
- For Europe and the CIS, it is the last Sunday in March to last Sunday
- in September.
- China uses April 12th to Sept 12th.
- Australia and New Zealand probably use last Sunday in October to last
- Sunday in March, but will have to check this out.
-
- Compute the first Sunday in April and last Sunday in October for the
- DST adjustment. Don't bother if daylight flag is not set.
- This routine must be called once before dst() is used and in the
- unlikely event that your computer never crashes, it must be called
- once per year after that.
- last_dstyear saves the last year that dstdates was called so you can
- add some code to check that the year hasn't changed
- */
- int last_dstyear;
- dstdates()
- {
- short days;
- time_t ltime;
- register struct tm *tp;
- short find_sunday;
-
- find_sunday = 1;
- if(!daylight)return;
-
- time(<ime);
- tp = localtime(<ime);
- last_dstyear = tp->tm_year;
- switch(toupper(daylight)) {
- case 'D':
- dst_start = dpm[3]; /* first Sunday in April */
- dst_end = dpm[10]-7; /* last Sunday in October */
- break;
- case 'U':
- dst_start = dpm[3] - 7; /* end of March */
- dst_end = dpm[10] - 7; /* end of Oct */
- break;
- case 'E':
- dst_start = dpm[3] - 7; /* End of march */
- dst_end = dpm[9] - 7; /* End of Sept */
- break;
- case 'C':
- dst_start = dpm[3]+11; /* Apr 12 */
- dst_end = dpm[9]+11; /* Sep 12 */
- find_sunday = 0; /* Don't look for Sunday */
- break;
- }
- /* Check for leap year */
- /* Technically, this calculation is incorrect. It does not check for
- years ending in 00 which are not leap years. But the year 2000
- IS a leap year, so the error won't hit until the year 2100 and
- I won't be around to collect bug reports.
- */
- if((tp->tm_year%4) == 0){
- dst_start += 1;
- dst_end += 1;
- }
- if(find_sunday) {
- days = (dst_start + tp->tm_wday)%7;
- if(days)dst_start += 7 - days;
-
- days = (dst_end + tp->tm_wday)%7;
- if(days)dst_end += 7 - days;
- }
-
- /* Adjust the days so that Jan 1st is day #1 instead of the zero returned
- by the localtime() routine
- */
- dst_start++;
- dst_end++;
- }
-